package com.csun.cmny.provider.service.impl;

import com.csun.cmny.base.dto.LoginAuthDto;
import com.csun.cmny.base.enums.ErrorCodeEnum;
import com.csun.cmny.core.support.BaseService;
import com.csun.cmny.provider.dao.DmcAppSleepDataRecordMapper;
import com.csun.cmny.provider.exceptions.DmcBizException;
import com.csun.cmny.provider.model.constant.OldmanAppConstant;
import com.csun.cmny.provider.model.domain.*;
import com.csun.cmny.provider.model.dto.alert.DeviceAlertPageQuery;
import com.csun.cmny.provider.model.dto.app.AppSleepDateQueryDto;
import com.csun.cmny.provider.model.dto.csunsleep.CsunSleepDataActionQueryDto;
import com.csun.cmny.provider.model.dto.csunsleep.CsunSleepDataInBedQueryDto;
import com.csun.cmny.provider.model.entity.TimeRange;
import com.csun.cmny.provider.model.vo.app.*;
import com.csun.cmny.provider.service.*;
import com.csun.cmny.provider.utils.DateUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.Date;
import java.util.LinkedList;
import java.util.List;

@Service
@Slf4j
@Transactional
public class DmcAppSleepDataRecordServiceImpl extends BaseService<DmcAppSleepDataRecord> implements DmcAppSleepDataRecordService {

    @Resource
    private DmcAppSleepDataRecordMapper dmcAppSleepDataRecordMapper;

    @Resource
    private DmcCsunSleepDataInBedService dmcCsunSleepDataInBedService;

    @Resource
    private DmcCsunSleepDataActionService dmcCsunSleepDataActionService;

    @Resource
    private DmcAppSleepRangeRecordService dmcAppSleepRangeRecordService;

    @Resource
    private DmcDeviceUserBindService dmcDeviceUserBindService;

    @Resource
    private DmcCsunSleepDataHiService dmcCsunSleepDataHiService;

    @Resource
    private DmcDeviceAlertService dmcDeviceAlertService;

    @Override
    public Integer saveAppSingleDaySleepData(Long deviceId, String date) {

        //将获取的日期对象转化为从前一天12:00到今日12：00的时间对象
        TimeRange countSleepTimeRange = DateUtil.getYesterDayAndTodayDate(date);

        CsunSleepDataInBedQueryDto inBedQueryDto = new CsunSleepDataInBedQueryDto();
        inBedQueryDto.setDeviceId(deviceId);
        inBedQueryDto.setInBed(0);
        inBedQueryDto.setPageSize(65535);
        inBedQueryDto.setStartQueryTime(countSleepTimeRange.getStartTime());
        inBedQueryDto.setEndQueryTime(countSleepTimeRange.getEndTime());
        List<DmcCsunSleepDataInBed> dmcCsunSleepDataInBeds = dmcCsunSleepDataInBedService.queryCsunSleepDataInBedList(inBedQueryDto);

        //创建翻身查询对象
        CsunSleepDataActionQueryDto actionQuery = new CsunSleepDataActionQueryDto();
        actionQuery.setDeviceId(deviceId);
        actionQuery.setPageSize(65535);
        actionQuery.setStartQueryTime(countSleepTimeRange.getStartTime());
        actionQuery.setEndQueryTime(countSleepTimeRange.getEndTime());

        //查询当日翻身时间信息
        List<DmcCsunSleepDataAction> actionList = dmcCsunSleepDataActionService.queryCsunSleepDataActionList(actionQuery);

        if(dmcCsunSleepDataInBeds.size()>0 && actionList.size()>0){

            //睡眠结果数据
            DmcAppSleepDataRecord appSleepDataRecord = new DmcAppSleepDataRecord();

            //睡眠时间段数据
            List<DmcAppSleepRangeRecord> appSleepRangeRecordList = new LinkedList<>();

            //定义在床时长
            Double countInBedTime = 0.000;

            //定义睡眠时长
            Double countSleepTime = 0.000;

            //定义当日最佳入睡时间，晚于此时间的第一次入睡时间为当天夜间入睡时间
            Date fallAsleepTimeStandard = DateUtil.transformDateStringToYesterDayDate(date , OldmanAppConstant.BEST_FALL_ASLEEP_TIME);

            //定义今日早上最佳起床时间，晚于此时间的第一次离床为起床时间；
            Date getBedTimeStandard = DateUtil.transformDateStringToDate(date,OldmanAppConstant.BEST_GET_BED_TIME);

            //内层循环指针暂存变量
            int temp = 0;

            //计算在床状态下的翻身间隔时间
            for(int i = 0,j = dmcCsunSleepDataInBeds.size();i<j;i++){

                //在床时长
                long inBedDuration = dmcCsunSleepDataInBeds.get(i).getDuration();

                //下床时刻
                Date inBedEndTime = dmcCsunSleepDataInBeds.get(i).getCreatedTime();

                //实际上床时刻 = 下床时刻 - 在床时长
                Date actualInBedStartTime = DateUtil.dateSubstractSeconds(inBedEndTime,(int)inBedDuration);

                //第一次计算时，上床时长早于统计开始时长，将上床时间设置为统计开始时间
                //之后按实际上床时刻计算
//                Date inBedStartTime = i==0?countSleepTimeRange.getStartTime():actualInBedStartTime;
                Date inBedStartTime = actualInBedStartTime.before(countSleepTimeRange.getStartTime())?countSleepTimeRange.getStartTime():actualInBedStartTime;

                //获取起床时间
                if(appSleepDataRecord.getGetBedTime() == null && inBedEndTime.after(getBedTimeStandard)){
                    appSleepDataRecord.setGetBedTime(DateUtil.dateToString(inBedEndTime));
                }

//                countInBedTime += ((double) (inBedEndTime.getTime() -  inBedStartTime.getTime()))/(60*1000);

                //如果该次翻身时间早于本段下床时间
                for(int k=temp,h = actionList.size();k<actionList.size() && actionList.get(k).getActionTime().before(inBedEndTime);k++){

                    //定义翻身时刻
                    Date actionTime = actionList.get(k).getActionTime();

                    if(actionTime.after(inBedStartTime)){

                        //定义该次翻身到上次翻身的间隔时长
                        long actionDuration = actionList.get(k).getDuration();

                        //定义上次翻身时间
                        Date lasteActionTime = DateUtil.dateSubstractSeconds(actionTime,(int)actionDuration);

                        //定义睡眠开始时刻
                        Date sleepStartTime = lasteActionTime.before(inBedStartTime)?inBedStartTime:lasteActionTime;

                        //获取入睡时间
                        if(appSleepDataRecord.getFallAsleepTime() == null && sleepStartTime.after(fallAsleepTimeStandard)){
                            appSleepDataRecord.setFallAsleepTime(DateUtil.dateToString(sleepStartTime));
                        }

                        //定义睡眠范围
                        DmcAppSleepRangeRecord appSleepRangeRecord = caculateSleepTime(sleepStartTime, actionTime);
                        appSleepRangeRecord.setDeviceId(deviceId);
                        appSleepRangeRecord.setDate(date);

                        //如果是睡眠状态，加入睡眠时间到总睡眠时间
                        if(appSleepRangeRecord.getStatus() == OldmanAppConstant.LIGHT_SLEEP_STATUS || appSleepRangeRecord.getStatus() == OldmanAppConstant.DEEP_SLEEP_STATUS){
                            countSleepTime += appSleepRangeRecord.getSleepTime();
                        }
                        countInBedTime += appSleepRangeRecord.getSleepTime();

                        //将该段睡眠加入睡眠统计
                        appSleepRangeRecordList.add(appSleepRangeRecord);

                        //如果该次【体动时间】的下次【体动时间】超过或等于【下床时间】，那么该次【体动时间】到【下床时间】的这段【睡眠时长】需要单独计算
                        if(k+1 < actionList.size()){
                            if(actionList.get(k+1).getActionTime().compareTo(inBedEndTime) >= 0){

                                //定义睡眠范围
                                DmcAppSleepRangeRecord thisLastAppSleepRangeRecord = caculateSleepTime(actionTime, inBedEndTime);
                                thisLastAppSleepRangeRecord.setDeviceId(deviceId);
                                thisLastAppSleepRangeRecord.setDate(date);

                                //如果是睡眠状态，加入睡眠时间到总睡眠时间
                                if(thisLastAppSleepRangeRecord.getStatus() == OldmanAppConstant.LIGHT_SLEEP_STATUS || thisLastAppSleepRangeRecord.getStatus() == OldmanAppConstant.DEEP_SLEEP_STATUS){
                                    countSleepTime += thisLastAppSleepRangeRecord.getSleepTime();
                                }
                                countInBedTime += thisLastAppSleepRangeRecord.getSleepTime();
                                //将该段睡眠加入睡眠统计
                                appSleepRangeRecordList.add(thisLastAppSleepRangeRecord);
                            }
                        }else{
                            //定义睡眠范围
                            DmcAppSleepRangeRecord thisLastAppSleepRangeRecord = caculateSleepTime(actionTime, inBedEndTime);
                            thisLastAppSleepRangeRecord.setDeviceId(deviceId);
                            thisLastAppSleepRangeRecord.setDate(date);

                            //如果是睡眠状态，加入睡眠时间到总睡眠时间
                            if(thisLastAppSleepRangeRecord.getStatus() == OldmanAppConstant.LIGHT_SLEEP_STATUS || thisLastAppSleepRangeRecord.getStatus() == OldmanAppConstant.DEEP_SLEEP_STATUS){
                                countSleepTime += thisLastAppSleepRangeRecord.getSleepTime();
                            }
                            countInBedTime += thisLastAppSleepRangeRecord.getSleepTime();
                            //将该段睡眠加入睡眠统计
                            appSleepRangeRecordList.add(thisLastAppSleepRangeRecord);
                        }
                    }
                    //如果该次翻身时间晚于本段上床时间 且开始统计时间小于翻身时间
                    //调整指针位置，下一次循环时，不需要重新循环
                    temp = k;
                }

                //计算睡眠得分
                int sleepGrade = countSleepTime>OldmanAppConstant.BEST_SLEEP_TIME?(int)(OldmanAppConstant.BEST_SLEEP_TIME/countSleepTime*100):(int)(countSleepTime/OldmanAppConstant.BEST_SLEEP_TIME*100);
                appSleepDataRecord.setSleepgrade(sleepGrade);
            }

            int rangRet = dmcAppSleepRangeRecordService.batchSave(appSleepRangeRecordList);

            //睡眠评分数据
            appSleepDataRecord.setCountActionTimes(actionList.size());
            appSleepDataRecord.setCountInBedTime(countInBedTime);
            appSleepDataRecord.setCountSleepTime(countSleepTime);
            appSleepDataRecord.setDeviceId(deviceId);
            appSleepDataRecord.setDate(date);
            int ret =  save(appSleepDataRecord);
            return ret;
        }
        return 0;
    }

    @Override
    public AppCountSleepDataVo getSleepDataByDeviceIdAndDate(AppSleepDateQueryDto appSleepDateQueryDto) {

        //查询当天数据
        DmcAppSleepDataRecord todaySleepData = new DmcAppSleepDataRecord();
        todaySleepData.setDeviceId(appSleepDateQueryDto.getDeviceId());
        todaySleepData.setDate(appSleepDateQueryDto.getDate());
        todaySleepData = selectOne(todaySleepData);

        if(todaySleepData == null){
            throw new DmcBizException(ErrorCodeEnum.DMC10067009);
        }
        //前七天时间范围
        TimeRange timeRange = DateUtil.getTodayDateAndBeforeSevenDaysDate(appSleepDateQueryDto.getDate());

        //历史数据查询
        AppSleepDateQueryDto historyQuery = new AppSleepDateQueryDto();
        historyQuery.setDeviceId(appSleepDateQueryDto.getDeviceId());
        historyQuery.setQueryStartTime(timeRange.getStartTime());
        historyQuery.setQueryEndTime(timeRange.getEndTime());
        List<AppSleepDataRecordVo> historyRecord = getHistroySleepData(historyQuery);

        //早起时间
        double countGetUpEarlyTime = 0;
        //晚睡时间
        double countFallAsleepLateTime = 0;
        //睡眠时长
        double countHistorySleepTime = 0;
        //往日分数
        double byGoneGrade= 0;

        for(AppSleepDataRecordVo historyItem : historyRecord){
            if(historyItem.getGetBedTime() != null && todaySleepData.getGetBedTime()!= null){
                countGetUpEarlyTime += DateUtil.calculateSubtract(historyItem.getGetBedTime(),todaySleepData.getGetBedTime());
            }
            if(todaySleepData.getFallAsleepTime() != null && historyItem.getFallAsleepTime()!= null){
                countFallAsleepLateTime += DateUtil.calculateSubtract(todaySleepData.getFallAsleepTime(),historyItem.getFallAsleepTime());
            }
            countHistorySleepTime += historyItem.getCountSleepTime();
            byGoneGrade += historyItem.getSleepgrade();
        }

        //获取当前月份
        String month = DateUtil.getYearAndMonth();
        AppSleepDataRecordVo theHighestGradeDayData = getHighestGradeDayDataByMonth(appSleepDateQueryDto.getDeviceId(),month);
        AppSleepDataRecordVo theLowestGradeDayData = getLowestGradeDayDataByMonth(appSleepDateQueryDto.getDeviceId(), month);

        //历史统计天数
        int days = historyRecord.size();

        //填充数据
        AppCountSleepDataVo appCountSleepDataVo = new AppCountSleepDataVo();
        if(days > 0){
            appCountSleepDataVo.setCountFallAsleepLateTime(countFallAsleepLateTime/days);
            appCountSleepDataVo.setCountGetUpEarlyTime(countGetUpEarlyTime/days);
            appCountSleepDataVo.setCountHistorySleepTime(countHistorySleepTime/days);
            appCountSleepDataVo.setByGoneAverageGrade(byGoneGrade/days);
        }
        appCountSleepDataVo.setTodaySleepData(todaySleepData);
        appCountSleepDataVo.setDays(days);
        appCountSleepDataVo.setTheHighestGradeDayData(theHighestGradeDayData);
        appCountSleepDataVo.setTheLowestGradeDayData(theLowestGradeDayData);
        return appCountSleepDataVo;
    }

    @Override
    public List<AppSleepDataRecordVo> getHistroySleepData(AppSleepDateQueryDto appSleepDateQueryDto) {

        List<AppSleepDataRecordVo> appSleepDataRecordList = dmcAppSleepDataRecordMapper.getHistroySleepData(appSleepDateQueryDto);

        return appSleepDataRecordList;
    }

    @Override
    public AppAlertCountVo getAlertCount(AppSleepDateQueryDto appSleepDateQueryDto, LoginAuthDto loginAuthDto) {

        Long deviceId = appSleepDateQueryDto.getDeviceId();
        DmcDeviceUserBind dmcDeviceUserBind = new DmcDeviceUserBind();
        dmcDeviceUserBind.setUserId(loginAuthDto.getUserId());
        dmcDeviceUserBind.setDeviceId(deviceId);
        dmcDeviceUserBind = dmcDeviceUserBindService.selectOne(dmcDeviceUserBind);

        if(dmcDeviceUserBind == null){
            throw new DmcBizException(ErrorCodeEnum.DMC10067003);
        }

        //设置查询条件
        if(dmcDeviceUserBind.getActionTimesThreshold() == null){
            throw new DmcBizException(ErrorCodeEnum.DMC10067010);
        }else{
            appSleepDateQueryDto.setActionTimesThreshold(dmcDeviceUserBind.getActionTimesThreshold());
        }
        if(dmcDeviceUserBind.getMaxBreathThreshold() == null || dmcDeviceUserBind.getMinBreathThreshold() == null){
            throw new DmcBizException(ErrorCodeEnum.DMC10067012);
        }else{
            appSleepDateQueryDto.setMaxBreathThreshold(dmcDeviceUserBind.getMaxBreathThreshold());
            appSleepDateQueryDto.setMinBreathThreshold(dmcDeviceUserBind.getMinBreathThreshold());
        }
        if(dmcDeviceUserBind.getMaxHeartbeatThreshold() == null || dmcDeviceUserBind.getMinHeartbeatThreshold() == null){
            throw new DmcBizException(ErrorCodeEnum.DMC10067011);
        }else{
            appSleepDateQueryDto.setMaxHeartbeatThreshold(dmcDeviceUserBind.getMaxHeartbeatThreshold());
            appSleepDateQueryDto.setMinHeartbeatThreshold(dmcDeviceUserBind.getMinHeartbeatThreshold());
        }
        appSleepDateQueryDto.setInBed(0);
        appSleepDateQueryDto.setStatus("offline");
        appSleepDateQueryDto.setQueryEndTime(DateUtil.dateAddSeconds(appSleepDateQueryDto.getQueryEndTime(),43199));

        DeviceAlertPageQuery deviceAlertPageQuery = new DeviceAlertPageQuery();
        BeanUtils.copyProperties(appSleepDateQueryDto,deviceAlertPageQuery);

        //统计报警次数
        Integer heartbeatAlertTimes = dmcCsunSleepDataHiService.countHeartbeatAlertTimes(appSleepDateQueryDto);
        //离床报警
        deviceAlertPageQuery.setStartQueryTime(appSleepDateQueryDto.getQueryStartTime());
        deviceAlertPageQuery.setEndQueryTime(appSleepDateQueryDto.getQueryEndTime());
        deviceAlertPageQuery.setPageSize(65536);
        deviceAlertPageQuery.setAlertType(11);
        Integer leaveBedAlertTimes = dmcDeviceAlertService.countAlertTimesByTypeAndTime(deviceAlertPageQuery);
        deviceAlertPageQuery.setAlertType(8);
        Integer actionAlertTimes = dmcDeviceAlertService.countAlertTimesByTypeAndTime(deviceAlertPageQuery);
        Integer breathAlertTimes = dmcCsunSleepDataHiService.countBreathAlertTimes(appSleepDateQueryDto);
        deviceAlertPageQuery.setAlertType(10);
        Integer offlineTimes = dmcDeviceAlertService.countAlertTimesByTypeAndTime(deviceAlertPageQuery);

        List<AppSleepDataRecordVo> vos = getHistroySleepData(appSleepDateQueryDto);
        AppAlertCountVo countVo = new AppAlertCountVo();

        //计算该时间范围睡眠数据
        double countTotalSleepTime = 0;
        double countTotalSleepGrade = 0;
        if(vos.size() > 0){
            for(AppSleepDataRecordVo vo : vos){
                countTotalSleepTime += vo.getCountSleepTime();
                countTotalSleepGrade += vo.getSleepgrade();
            }
            countVo.setCountSleepGrade(countTotalSleepGrade/vos.size());
            countVo.setAppSleepDataRecordVoList(vos);
            countVo.setCountTotalSleepTime(countTotalSleepTime);
        }
        countVo.setHeartbeatAlertTimes(heartbeatAlertTimes);
        countVo.setLeaveBedAlertTimes(leaveBedAlertTimes);
        countVo.setActionAlertTimes(actionAlertTimes);
        countVo.setBreathAlertTimes(breathAlertTimes);
        countVo.setOfflineTimes(offlineTimes);
        return countVo;
    }

    @Override
    public AppDataCompareVo getThisCycleDataAndLastCycleData(AppSleepDateQueryDto appSleepDateQueryDto, LoginAuthDto loginAuthDto) {

        //将结束查询时间设置为当天23:59:59
        appSleepDateQueryDto.setQueryEndTime(DateUtil.dateAddSeconds(appSleepDateQueryDto.getQueryEndTime(),43199));

        //查询本周期数据
        List<AppSleepDataRecordVo> thisSleepDataList = getHistroySleepData(appSleepDateQueryDto);
        //计算本周期天数
        Long days = (appSleepDateQueryDto.getQueryEndTime().getTime()-appSleepDateQueryDto.getQueryStartTime().getTime())/(1000*60*60*24);
        //计算上周期起止时间
        Date historyEndTime = DateUtil.dateSubstractDays(appSleepDateQueryDto.getQueryStartTime(), 1);
        Date historyStartTime = DateUtil.dateSubstractDays(appSleepDateQueryDto.getQueryStartTime(), days.intValue()+1);

        appSleepDateQueryDto.setQueryStartTime(historyStartTime);
        appSleepDateQueryDto.setQueryEndTime(historyEndTime);

        //查询上周期数据
        List<AppSleepDataRecordVo> histroySleepDataList = getHistroySleepData(appSleepDateQueryDto);

        //本周起睡眠时长
        double thisCycleSleepTimeCount = 0;
        //本周期平均分
        double thisCycleSleepGradeAverage = 0;
        //本周期天数
        int thisCycleDays = thisSleepDataList.size();
        //上周期天数
        int lastCycleDays = histroySleepDataList.size();
        //上周期睡眠时长
        double lastCycleSleepTimeCount = 0;
        //上周期平均分
        double lastCycleSleepGradeAverage = 0;

        //定义返回对象
        AppDataCompareVo vo = new AppDataCompareVo();

        //计算睡眠数据
        if(thisCycleDays > 0){
            for(AppSleepDataRecordVo recordVo : thisSleepDataList){
                thisCycleSleepTimeCount += recordVo.getCountSleepTime();
                thisCycleSleepGradeAverage += recordVo.getSleepgrade();
            }
            thisCycleSleepGradeAverage = thisCycleSleepGradeAverage/thisCycleDays;
        }

        if(lastCycleDays > 0){
            for(AppSleepDataRecordVo historyRecordVo : histroySleepDataList){
                lastCycleSleepTimeCount += historyRecordVo.getCountSleepTime();
                lastCycleSleepGradeAverage += historyRecordVo.getSleepgrade();
            }
            lastCycleSleepGradeAverage = lastCycleSleepGradeAverage/lastCycleDays;
        }
        vo.setLastCycleDays(lastCycleDays);
        vo.setLastCycleSleepGradeAverage(lastCycleSleepGradeAverage);
        vo.setLastCycleSleepTimeCount(lastCycleSleepTimeCount);
        vo.setThisCycleDays(thisCycleDays);
        vo.setThisCycleSleepGradeAverage(thisCycleSleepGradeAverage);
        vo.setThisCycleSleepTimeCount(thisCycleSleepTimeCount);
        return vo;
    }

    //根据起止时间计算睡眠时长
    public DmcAppSleepRangeRecord caculateSleepTime(Date startTime,Date endTime){

        DmcAppSleepRangeRecord appSleepRangeRecord = new DmcAppSleepRangeRecord();

        //计算睡眠时长
        double sleepDuration = ((double)endTime.getTime() - (double) startTime.getTime())/(1000*60);
        appSleepRangeRecord.setSleepTime(sleepDuration);
        appSleepRangeRecord.setStartTime(DateUtil.dateToString(startTime));
        appSleepRangeRecord.setEndTime(DateUtil.dateToString(endTime));

        //判断睡眠状态
        if(sleepDuration >= OldmanAppConstant.DEEP_SLEEP_STANDARD){
            appSleepRangeRecord.setStatus(OldmanAppConstant.DEEP_SLEEP_STATUS);
        }else if(sleepDuration>=OldmanAppConstant.LIGHT_SLEEP_STANRDARD && sleepDuration < OldmanAppConstant.DEEP_SLEEP_STANDARD){
            appSleepRangeRecord.setStatus(OldmanAppConstant.LIGHT_SLEEP_STATUS);
        }else{
            appSleepRangeRecord.setStatus(OldmanAppConstant.AWAKE_STATUS);
        }
        return appSleepRangeRecord;
    }

    //查询当月分数最高的一条记录
    public AppSleepDataRecordVo getHighestGradeDayDataByMonth(Long deviceId , String month){
        return dmcAppSleepDataRecordMapper.getHighestGradeDayDataByMonth(deviceId,month);
    }

    //查询当月分数最低的一条记录
    public AppSleepDataRecordVo getLowestGradeDayDataByMonth(Long deviceId , String month){
        return dmcAppSleepDataRecordMapper.getLowestGradeDayDataByMonth(deviceId,month);
    }

}
